/*
 *  AbstractLine.cpp
 *  SoundController0002
 *
 *  Created by jiro on 11/10/02.
 *  Copyright 2011 jiro music. All rights reserved.
 *
 */

#include "AbstractLine.h"
#include "ConcreteNote.h"
#include "ConcreteLine.h"

namespace sc
{
namespace system0039
{

	void AbstractLine::AddNote( const ::sc::system0039::AbstractNote& note )
	{
		notes.push_back( note );
	}

	int AbstractLine::GetConcreteLineCount() const
	{
		const int noteCount = notes.size();
		int totalLineCount = 1;
		std::vector< int > indexList( noteCount );
		std::vector< std::vector< ConcreteNote > > concreteNotesList( noteCount );
		for ( int i = 0; i < noteCount; i++ )
		{
			const AbstractNote& note = notes[ i ];
			std::vector< ConcreteNote >& concreteNotes = concreteNotesList[ i ];

			note.GetConcreteNotes( concreteNotes );
			totalLineCount *= concreteNotes.size();
			indexList[ i ] = 0;
		}
		return totalLineCount;
	}

	void AbstractLine::GetConcreteLines( std::vector< ConcreteLine >& lines ) const
	{
		//	initialize
		const int noteCount = notes.size();
		int totalLineCount = 1;
		std::vector< int > indexList( noteCount );
		std::vector< std::vector< ConcreteNote > > concreteNotesList( noteCount );
		for ( int i = 0; i < noteCount; i++ )
		{
			const AbstractNote& note = notes[ i ];
			std::vector< ConcreteNote >& concreteNotes = concreteNotesList[ i ];

			note.GetConcreteNotes( concreteNotes );
			totalLineCount *= concreteNotes.size();
			indexList[ i ] = 0;
		}
		lines.resize( totalLineCount );

		//	calc lines
		int lineIndex = 0;
		bool isContinue = true;
		const int lastIndex = noteCount - 1;
		while ( true )
		{
//			CoutIndexList( indexList );

			//	add line
			ConcreteLine& line = lines[ lineIndex ];
			for ( int j = 0; j < noteCount; j++ )
			{
				line.push_back( concreteNotesList[ j ].at( indexList[ j ] ) );
			}

			//	update index
			int indexIndex = lastIndex;
			indexList[ lastIndex ]++;
			while ( indexList[ indexIndex ] == concreteNotesList[ indexIndex ].size() )
			{
				if ( indexIndex == 0 )
				{
					isContinue = false;
					break;
				}

				indexList[ indexIndex ] = 0;
				indexIndex--;
				indexList[ indexIndex ]++;
			}
			if ( not isContinue )
			{
				break;
			}
			lineIndex++;
		}
	}
	
	void AbstractLine::Clear()
	{
		notes.clear();
	}

	void AbstractLine::CoutIndexList( const std::vector< int >& indexList )
	{
		for ( int j = 0; j < indexList.size(); j++ )
		{
			std::cout << indexList[ j ] << ", ";
		}
		std::cout << "\n";
	}

	std::string AbstractLine::ToString( int tabCount ) const
	{
		std::stringstream ss;
		for ( int i = 0; i < tabCount; i++ )
		{
			ss << "\t";
		}
		ss << "AbstractLine\n";
		for ( int i = 0, count = notes.size(); i < count; i++ )
		{
			ss << notes[ i ].ToString( tabCount + 1 ) << "\n";
		}
		return ss.str();
	}
}
}
